/**
 * \file Point3D.h
 * \brief Point3D definition and declaration class
 * \author Edouard ROGE
 * \date 12 septembre 2010
 */

#ifndef _POINT3D_
#define _POINT3D_

#include "Core/Memory/HeapObject.h"

namespace Math
{
	namespace M3D
	{
		/**
		 * \class Point3D
		 * \brief class with template to instantiate a 3D point
		 */
		template < class T >
		class Point3D : public Core::Memory::HeapObject
		{
		public:
			/**
			 * \union union
			 * \brief union of 3 values (x y and z) and a array with 3 elements
			 */
			union
			{
				/**
				 * \struct struct
				 * \brief x y and z
				 */
				struct
				{
					/** x */
					T x;
					/** y */
					T y;
					/** z */
					T z;
				};

				/** array of 3 elements */
				T	Value[3];
			};

		public:
			/**
			 * \fn Point3D();
			 * \brief Default constructor
			 */
			Point3D();

			/**
			 * \fn Point3D(T _x, T _y, T _z);
			 * \param _x copy _x in x
			 * \param _y copy _y in y
			 * \param _z copy _z in z
			 * \brief Constructor with parameter
			 */
			Point3D(T _x, T _y, T _z);

			/**
			 * \fn Point3D(const Point3D<T> & p);
			 * \param p point to copy
			 * Copy constructor
			 */
			Point3D(const Point3D<T> & p);

			/**
			 * \fn ~Point3D();
			 * \brief Destructor
			 */
			~Point3D();

			/**
			 * \fn void Set(T _x, T _y, T _z);
			 * \param _x copy _x in x
			 * \param _y copy _y in y
			 * \param _z copy _z in z
			 * \brief Set 3d Point values
			 */
			void Set(T _x, T _y, T _z);

			/**
			 * \fn operator T* ();
			 * \return the 3d point value
			 * \brief retrieve the 3d point value in a array of T.
			 * Useful for casting
			 */
			operator T* ();

			/**
			 * \fn operator const T* () const
			 * \return the 3d point value
			 * \brief retrieve the 3d point value in a array of T.
			 * Useful for casting
			 */
			operator const T* () const;

			/**
			 * \fn Point3D<T> & operator = (const Point3D<T> & _o);
			 * \param _o copy _o in (*this)
			 * \return (*this) with the new value
			 * \brief operator =
			 */
			Point3D<T> & operator = (const Point3D<T> & _o);

			/**
			 * \fn template < class T1 > friend bool operator == (const Point3D<T1> & _o1, const Point3D<T1> & _o2);
			 * \param _o1 3d point
			 * \param _o2 3d point
			 * \return true if _o1 is equal to _o2
			 * \brief operator ==
			 */
			template < class T1 > friend bool operator == (const Point3D<T1> & _o1, const Point3D<T1> & _o2);

			/**
			 * \fn template < class T1 > friend bool operator != (const Point3D<T1> & _o1, const Point3D<T1> & _o2);
			 * \param _o1 3d point
			 * \param _o2 3d point
			 * \return true if _o1 is not equal to _o2
			 * \brief operator !=
			 */
			template < class T1 > friend bool operator != (const Point3D<T1> & _o1, const Point3D<T1> & _o2);

		};

		/** Point3D of float */
		typedef Point3D<float>	Point3f;

		/** Point3D of integer */
		typedef Point3D<int>	Point3i;

		template < class T >
		Point3D< T >::Point3D()
			:x(0), y(0), z(0)
		{
		}

		template < class T >
		Point3D< T >::Point3D(T _x, T _y, T _z)
			: x(_x), y(_y), z(_z)
		{
		}

		template < class T >
		Point3D< T >::Point3D(const Point3D<T> & p)
			: x(p.x), y(p.y), z(p.z)
		{
		}

		template < class T >
		Point3D< T >::~Point3D()
		{
		}

		template < class T >
		void Point3D< T >::Set(T _x, T _y, T _z)
		{
			x = _x;
			y = _y;
			z = _z;
		}

		template < class T >
		Point3D< T >:: operator T* ()
		{
			return Value;
		}

		template < class T >
		Point3D< T >::operator const T* () const
		{
			return Value;
		}

		template < class T >
		Point3D<T> & Point3D< T >::operator = (const Point3D<T> & _o)
		{
			x = _o.x;
			y = _o.y;
			z = _o.z;
			return (*this);
		}
	}
}

/**
 * \fn template < class T1 > bool operator == (const Math::M3D::Point3D<T1> & _o1, const Math::M3D::Point3D<T1> & _o2);
 * \param _o1 3d point
 * \param _o2 3d point
 * \return true if _o1 is equal to _o2
 * \brief operator ==
 */
template < class T1 >
bool operator == (const Math::M3D::Point3D<T1> & _o1, const Math::M3D::Point3D<T1> & _o2)
{
	return ( _o1.x == _o2.x && _o1.y == _o2.y && _o1.z == _o2.z );
}

/**
 * \fn template < class T1 > friend bool operator != (const Math::M3D::Point3D<T1> & _o1, const Math::M3D::Point3D<T1> & _o2);
 * \param _o1 3d point
 * \param _o2 3d point
 * \return true if _o1 is not equal to _o2
 * \brief operator !=
 */
template < class T1 >
bool operator != (const Math::M3D::Point3D<T1> & _o1, const Math::M3D::Point3D<T1> & _o2)
{
	return !(_o1 == _o2);
}

#endif // _POINT3D_
